import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:path/path.dart' as path;
import 'package:syncfusion_flutter_pdf/pdf.dart';
import '../AI/tina_dart/BaseAPI.dart';
import 'file_serve.dart';
import 'docx_reader_service.dart';

/// 标签分析任务
class TagAnalysisTask {
  final String taskId;
  final String documentPath;
  final String documentName;
  final String category;
  bool isRunning;
  double progress;
  List<String> extractedTags;
  String? errorMessage;
  DateTime createdAt;

  TagAnalysisTask({
    required this.taskId,
    required this.documentPath,
    required this.documentName,
    required this.category,
    this.isRunning = false,
    this.progress = 0.0,
    this.extractedTags = const [],
    this.errorMessage,
    DateTime? createdAt,
  }) : createdAt = createdAt ?? DateTime.now();
}

/// 文档标签分析服务
class TagAnalysisService {
  static final TagAnalysisService _instance = TagAnalysisService._internal();
  factory TagAnalysisService() => _instance;
  TagAnalysisService._internal();

  final List<TagAnalysisTask> _analysisTasks = [];
  bool _isInitialized = false;
  
  // 依赖服务
  BaseAPI? _llm;
  FileServe? _fileServe;
  String? _appDataDir;
  
  // 分析参数
  static const int _chunkSize = 20000; // 20000字符步长
  
  List<TagAnalysisTask> get analysisTasks => List.unmodifiable(_analysisTasks);
  bool get isInitialized => _isInitialized;

  /// 初始化标签分析服务
  void initialize({
    required BaseAPI llm,
    required FileServe fileServe,
    required String appDataDir,
  }) {
    _llm = llm;
    _fileServe = fileServe;
    _appDataDir = appDataDir;
    _isInitialized = true;
    print('TagAnalysisService: 标签分析服务已初始化');
  }

  /// 添加文档标签分析任务
  String addDocumentTagAnalysis({
    required String documentPath,
    required String documentName,
    required String category,
  }) {
    if (!_isInitialized) {
      throw Exception('TagAnalysisService not initialized');
    }

    final taskId = 'tag_${DateTime.now().millisecondsSinceEpoch}';
    final task = TagAnalysisTask(
      taskId: taskId,
      documentPath: documentPath,
      documentName: documentName,
      category: category,
    );

    _analysisTasks.add(task);
    print('TagAnalysisService: 添加标签分析任务 - $documentName');

    // 在后台启动分析任务
    _runTagAnalysis(task);

    return taskId;
  }

  /// 执行标签分析任务
  Future<void> _runTagAnalysis(TagAnalysisTask task) async {
    try {
      task.isRunning = true;
      task.progress = 0.0;
      print('TagAnalysisService: 开始分析文档标签 - ${task.documentName}');

      // 读取文档内容
      final documentContent = await _readDocumentContent(task.documentPath);
      task.progress = 0.1;

      if (documentContent.isEmpty) {
        print('TagAnalysisService: 文档内容为空，跳过标签分析 - ${task.documentName}');
        task.isRunning = false;
        task.progress = 1.0;
        return;
      }

      // 分块处理文档内容
      final allTags = <String>{};
      final chunks = _splitIntoChunks(documentContent, _chunkSize);
      
      for (int i = 0; i < chunks.length; i++) {
        final chunk = chunks[i];
        print('TagAnalysisService: 分析第${i + 1}/${chunks.length}块内容');

        // 构建上下文，包含已提取的标签
        final contextTags = allTags.isNotEmpty ? 
          '已提取的标签：${allTags.join("、")}' : '';

        // 调用LLM分析当前块的标签
        final chunkTags = await _analyzeChunkTags(chunk, contextTags);
        allTags.addAll(chunkTags);

        // 更新进度
        task.progress = 0.1 + (0.8 * (i + 1) / chunks.length);
      }

      // 去除重复和相似的标签
      final finalTags = await _deduplicateTags(allTags.toList());
      task.extractedTags = finalTags;
      task.progress = 0.95;

      // 保存标签到文件系统
      await _saveDocumentTags(task.documentName, task.category, finalTags);
      
      task.progress = 1.0;
      task.isRunning = false;
      
      print('TagAnalysisService: 标签分析完成 - ${task.documentName}');
      print('TagAnalysisService: 提取到${finalTags.length}个标签: ${finalTags.join("、")}');

    } catch (e) {
      task.isRunning = false;
      task.errorMessage = e.toString();
      print('TagAnalysisService: 标签分析失败 - ${task.documentName}: $e');
    }
  }

  /// 读取文档内容
  Future<String> _readDocumentContent(String documentPath) async {
    try {
      final file = File(documentPath);
      if (!await file.exists()) {
        throw Exception('文档文件不存在: $documentPath');
      }

      final extension = path.extension(documentPath).toLowerCase();
      
      switch (extension) {
        case '.txt':
        case '.md':
          return await file.readAsString();
        case '.pdf':
          return await _readPdfContent(documentPath);
        case '.docx':
          return await _readDocxContent(documentPath);
        default:
          // 对于其他格式，尝试按文本读取
          try {
            return await file.readAsString();
          } catch (e) {
            print('TagAnalysisService: 无法读取文件格式: $extension');
            return '';
          }
      }
    } catch (e) {
      print('TagAnalysisService: 读取文档内容失败: $e');
      return '';
    }
  }

  /// 读取PDF文件内容
  Future<String> _readPdfContent(String pdfPath) async {
    try {
      final bytes = await File(pdfPath).readAsBytes();
      final document = PdfDocument(inputBytes: bytes);
      
      final StringBuffer buffer = StringBuffer();
      
      // 提取每一页的文本
      for (int i = 0; i < document.pages.count; i++) {
        final page = document.pages[i];
        final text = PdfTextExtractor(document).extractText(startPageIndex: i, endPageIndex: i);
        buffer.writeln(text);
      }
      
      document.dispose();
      
      final content = buffer.toString().trim();
      print('TagAnalysisService: PDF内容提取完成，长度: ${content.length}字符');
      return content;
      
    } catch (e) {
      print('TagAnalysisService: PDF内容提取失败: $e');
      return '';
    }
  }

  /// 读取DOCX文件内容
  Future<String> _readDocxContent(String docxPath) async {
    try {
      print('TagAnalysisService: 尝试读取DOCX文件: $docxPath');
      
      // 使用专门的DOCX读取服务
      final docxReader = DocxReaderService();
      final docxContent = await docxReader.readDocxFile(docxPath);
      
      print('TagAnalysisService: DOCX文件读取成功，内容长度: ${docxContent.content.length}字符');
      return docxContent.content;
      
    } catch (e) {
      print('TagAnalysisService: DOCX内容提取失败: $e');
      
      // 如果专门的读取器失败，尝试生成基础信息
      try {
        final file = File(docxPath);
        if (await file.exists()) {
          final fileName = path.basenameWithoutExtension(docxPath);
          final fileSize = await file.length();
          
          // 基于文件名生成一些基础标签内容
          final content = '''
文档名称: $fileName
文件类型: Microsoft Word文档
文件大小: ${(fileSize / 1024).toStringAsFixed(1)} KB

注意：DOCX文件内容提取失败，可能需要检查文件格式。
建议：将文档转换为PDF或TXT格式以获得更好的标签分析效果。
''';
          
          print('TagAnalysisService: 使用基础文件信息作为内容');
          return content;
        }
      } catch (fallbackError) {
        print('TagAnalysisService: 基础信息提取也失败: $fallbackError');
      }
      
      return '';
    }
  }

  /// 将文档内容分块
  List<String> _splitIntoChunks(String content, int chunkSize) {
    final chunks = <String>[];
    int start = 0;
    
    while (start < content.length) {
      int end = start + chunkSize;
      if (end > content.length) {
        end = content.length;
      }
      
      // 尝试在句号、感叹号或问号处分割，避免截断句子
      if (end < content.length) {
        final lastSentenceEnd = content.lastIndexOf(RegExp(r'[。！？.!?]'), end);
        if (lastSentenceEnd > start + chunkSize ~/ 2) {
          end = lastSentenceEnd + 1;
        }
      }
      
      chunks.add(content.substring(start, end));
      start = end;
    }
    
    return chunks;
  }

  /// 分析单个文档块的标签
  Future<List<String>> _analyzeChunkTags(String chunkContent, String contextTags) async {
    try {
      final prompt = '''
你是一个专业的知识标签提取助手。请仔细阅读以下文档内容，提取出最具代表性的核心知识标签。

严格要求：
1. 只提取3-5个最重要的标签，宁缺毋滥
2. 标签必须是具体的专业术语、技术概念或学科领域
3. 标签长度2-6个字，避免单字或过长标签
4. 优先级：专业术语 > 技术概念 > 学科领域 > 方法论
5. 严禁提取：形容词、动词、泛化词汇（如"重要"、"方法"、"技术"、"系统"等）
6. ${contextTags.isNotEmpty ? '避免与已有标签重复：$contextTags' : ''}
7. 只返回标签，用逗号分隔，无其他文字

文档内容：
$chunkContent

核心标签：''';

      final result = await _llm!.predict(
        sysPrompt: '你是专业的知识标签提取专家，擅长识别文档中最具价值的核心概念。你的目标是提取少而精的高质量标签。',
        inputText: prompt,
      );

      final content = result['content'].toString().trim();
      
      // 解析标签，更严格的过滤
      final tags = content
          .split(RegExp(r'[,，、]'))
          .map((tag) => tag.trim())
          .where((tag) => 
            tag.isNotEmpty && 
            tag.length >= 2 && 
            tag.length <= 8 &&
            !_isGenericTag(tag)
          )
          .take(5) // 限制每个块最多5个标签
          .toList();

      print('TagAnalysisService: 从文档块提取到${tags.length}个精选标签: ${tags.join("、")}');
      return tags;
      
    } catch (e) {
      print('TagAnalysisService: 分析文档块标签失败: $e');
      return [];
    }
  }

  /// 检查是否为泛化标签
  bool _isGenericTag(String tag) {
    final genericTags = {
      '重要', '关键', '主要', '基本', '核心', '常见', '一般', '普通',
      '方法', '技术', '系统', '工具', '平台', '框架', '模式', '策略',
      '问题', '解决', '实现', '应用', '使用', '操作', '处理', '管理',
      '分析', '研究', '学习', '理解', '掌握', '提高', '改进', '优化',
      '内容', '信息', '数据', '文档', '资料', '知识', '经验', '技巧'
    };
    
    return genericTags.contains(tag) || 
           tag.length == 1 || 
           RegExp(r'^[a-zA-Z]+$').hasMatch(tag); // 排除纯英文缩写
  }

  /// 去除重复和相似的标签，并进行最终精选
  Future<List<String>> _deduplicateTags(List<String> tags) async {
    if (tags.isEmpty) return [];

    try {
      // 先进行基础去重和频次统计
      final tagFrequency = <String, int>{};
      for (final tag in tags) {
        tagFrequency[tag] = (tagFrequency[tag] ?? 0) + 1;
      }

      // 按频次排序，优先保留出现频次高的标签
      final sortedTags = tagFrequency.entries
          .toList()
          ..sort((a, b) => b.value.compareTo(a.value));

      final candidateTags = sortedTags.map((e) => e.key).toList();
      
      // 如果标签数量已经很少，直接返回
      if (candidateTags.length <= 8) {
        print('TagAnalysisService: 标签数量适中，保留${candidateTags.length}个标签');
        return candidateTags;
      }

      // 使用LLM进行智能精选和去重
      final prompt = '''
请从以下标签中精选出最具代表性的核心标签。这些标签按重要性排序，频次越高越重要：

${candidateTags.take(20).toList().asMap().entries.map((e) => '${e.key + 1}. ${e.value} (出现${tagFrequency[e.value]}次)').join('\n')}

精选要求：
1. 最多保留5-8个最核心的标签
2. 优先保留专业术语和技术概念
3. 移除含义重复或相似的标签（如"深度学习"和"神经网络"只保留一个）
4. 移除过于宽泛的标签
5. 确保标签能够准确代表文档的核心主题
6. 只返回精选后的标签，用逗号分隔，无其他文字

精选标签：''';

      final result = await _llm!.predict(
        sysPrompt: '你是专业的知识标签精选专家，擅长从众多标签中挑选出最具代表性的核心标签。你的目标是少而精。',
        inputText: prompt,
      );

      final content = result['content'].toString().trim();
      final finalTags = content
          .split(RegExp(r'[,，、]'))
          .map((tag) => tag.trim())
          .where((tag) => tag.isNotEmpty && !_isGenericTag(tag))
          .take(8) // 最多8个标签
          .toList();

      print('TagAnalysisService: 最终精选出${finalTags.length}个核心标签: ${finalTags.join("、")}');
      return finalTags;
      
    } catch (e) {
      print('TagAnalysisService: 标签精选失败: $e');
      // 如果LLM精选失败，手动选择前6个最频繁的唯一标签
      final uniqueTags = tags.toSet().toList();
      final result = uniqueTags.take(6).toList();
      print('TagAnalysisService: 降级处理，保留${result.length}个标签');
      return result;
    }
  }

  /// 保存文档标签到文件系统
  Future<void> _saveDocumentTags(String documentName, String category, List<String> tags) async {
    try {
      if (!_isInitialized || _fileServe == null) {
        throw Exception('服务未初始化');
      }

      // 1. 更新全局标签文件 (tag.json)
      await _updateGlobalTagFile(documentName, tags);

      // 2. 更新分类文档JSON文件，添加标签信息
      await _updateCategoryDocumentTags(category, documentName, tags);

      // 3. 更新分类标签统计
      await _fileServe!.updateCategoryTagStats(category, tags);

    } catch (e) {
      print('TagAnalysisService: 保存标签失败: $e');
      rethrow;
    }
  }

  /// 更新全局标签文件
  Future<void> _updateGlobalTagFile(String documentName, List<String> tags) async {
    try {
      final cacheDir = Directory(path.join(_appDataDir!, 'cache'));
      final tagFile = File(path.join(cacheDir.path, 'tag.json'));

      Map<String, List<String>> tagData = {};

      // 读取现有标签数据
      if (await tagFile.exists()) {
        final content = await tagFile.readAsString();
        final jsonData = jsonDecode(content) as Map<String, dynamic>;
        
        // 转换为正确的数据结构
        for (final entry in jsonData.entries) {
          tagData[entry.key] = List<String>.from(entry.value as List);
        }
      }

      // 添加新文档的标签
      for (final tag in tags) {
        if (!tagData.containsKey(tag)) {
          tagData[tag] = [];
        }
        
        // 如果文档不在标签的文档列表中，添加它
        if (!tagData[tag]!.contains(documentName)) {
          tagData[tag]!.add(documentName);
        }
      }

      // 保存更新后的标签数据
      await tagFile.writeAsString(jsonEncode(tagData));
      print('TagAnalysisService: 全局标签文件已更新');

    } catch (e) {
      print('TagAnalysisService: 更新全局标签文件失败: $e');
      rethrow;
    }
  }

  /// 更新分类文档的标签信息
  Future<void> _updateCategoryDocumentTags(String category, String documentName, List<String> tags) async {
    try {
      final cacheDir = Directory(path.join(_appDataDir!, 'cache'));
      final categoryFile = File(path.join(cacheDir.path, '$category.json'));

      if (!await categoryFile.exists()) {
        print('TagAnalysisService: 分类文件不存在: $category.json');
        return;
      }

      // 读取分类文档数据
      final content = await categoryFile.readAsString();
      final documents = List<Map<String, dynamic>>.from(
        jsonDecode(content).map((doc) => Map<String, dynamic>.from(doc))
      );

      // 查找并更新对应文档的标签
      bool updated = false;
      for (int i = 0; i < documents.length; i++) {
        if (documents[i]['title'] == documentName) {
          documents[i]['tags'] = tags;
          updated = true;
          break;
        }
      }

      if (updated) {
        // 保存更新后的文档列表
        await categoryFile.writeAsString(jsonEncode(documents));
        print('TagAnalysisService: 分类文档标签已更新: $category/$documentName');
      } else {
        print('TagAnalysisService: 在分类中未找到文档: $category/$documentName');
      }

    } catch (e) {
      print('TagAnalysisService: 更新分类文档标签失败: $e');
      rethrow;
    }
  }

  /// 获取正在运行的分析任务数量
  int get activeAnalysisCount {
    return _analysisTasks.where((task) => task.isRunning).length;
  }

  /// 清理已完成的分析任务
  void clearCompletedTasks() {
    _analysisTasks.removeWhere((task) => !task.isRunning);
  }

  /// 根据标签获取文档列表
  Future<List<String>> getDocumentsByTag(String tag) async {
    try {
      final cacheDir = Directory(path.join(_appDataDir!, 'cache'));
      final tagFile = File(path.join(cacheDir.path, 'tag.json'));

      if (!await tagFile.exists()) {
        return [];
      }

      final content = await tagFile.readAsString();
      final tagData = jsonDecode(content) as Map<String, dynamic>;

      return List<String>.from(tagData[tag] ?? []);
    } catch (e) {
      print('TagAnalysisService: 获取标签文档失败: $e');
      return [];
    }
  }
} 